package com.ziyueyuwen.xiniao.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.ziyueyuwen.xiniao.base.exception.param.RequestParamNullException;
import com.ziyueyuwen.xiniao.bean.ZyCourseInfo;
import com.ziyueyuwen.xiniao.bean.page.PageData;
import com.ziyueyuwen.xiniao.bean.product.*;
import com.ziyueyuwen.xiniao.bean.ZyProductInfo;
import com.ziyueyuwen.xiniao.bean.ZyProductStage;
import com.ziyueyuwen.xiniao.bean.query.CourseQuery;
import com.ziyueyuwen.xiniao.bean.select.SelectBean;
import com.ziyueyuwen.xiniao.bean.vo.ZyClassVO;
import com.ziyueyuwen.xiniao.bean.vo.ZyCourseVO;
import com.ziyueyuwen.xiniao.dao.ZyClassInfoMapper;
import com.ziyueyuwen.xiniao.dao.ZyCourseInfoMapper;
import com.ziyueyuwen.xiniao.dao.ZyOrderMapper;
import com.ziyueyuwen.xiniao.dao.ZyProductInfoMapper;
import com.ziyueyuwen.xiniao.enums.*;
import com.ziyueyuwen.xiniao.service.ProductService;
import com.ziyueyuwen.xiniao.service.baseservice.product.ProductInfoBaseService;
import com.ziyueyuwen.xiniao.service.baseservice.product.ZyProductStageBaseService;
import com.ziyueyuwen.xiniao.util.DateUtil;
import com.ziyueyuwen.xiniao.util.PageDataUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

import static com.ziyueyuwen.xiniao.enums.CourseQuarterEnum.COURSE_SPRING;
import static com.ziyueyuwen.xiniao.enums.CourseQuarterEnum.COURSE_SUMMER;
import static com.ziyueyuwen.xiniao.enums.CourseQuarterEnum.COURSE_WINTER;
import static com.ziyueyuwen.xiniao.util.DateUtil.DEFAULT_FORMAT_PATTERN_5;

/**
 * @author wancheng  on 2019/2/21.
 */
@Service
public class ProductServiceImpl implements ProductService {

    @Autowired
    ProductInfoBaseService productInfoBaseService;
    @Autowired
    ZyProductStageBaseService zyProductStageBaseService;
    @Autowired
    ZyProductInfoMapper zyProductInfoMapper;
    @Autowired
    ZyCourseInfoMapper zyCourseInfoMapper;
    @Autowired
    ZyClassInfoMapper zyClassInfoMapper;
    @Autowired
    ZyOrderMapper orderMapper;

    @Override
    public void saveSelective(ProductSaveAO productSave) throws Exception {
        ZyProductInfo productInfo = getProduct(productSave);
        if (isSummerOrWinter(productInfo)) {
            if (productInfo.getStageId() == null) {
                throw new Exception("暑假班或寒假班请选择期");
            }
        } else {
            ZyProductStage stage = getStage(productSave);
            if (stage.getBeginDay() == null || stage.getEndDay() == null) {
                throw new RequestParamNullException("上课时间");
            }
            zyProductStageBaseService.saveUseGeneratedKeys(stage);
            productInfo.setStageId(stage.getId());
        }
        ZyProductInfo ifClassProduct = productInfoBaseService.selectOneByClassId(productInfo.getClassId());
        if (ifClassProduct != null) {
            throw new Exception("该班级已经关联商品");
        }
        productInfoBaseService.saveSelective(productInfo);

    }

    private Boolean isSummerOrWinter(ZyProductInfo productInfo) {
        if (productInfo.getType().equals(COURSE_SUMMER) || productInfo.getType().equals(CourseQuarterEnum.COURSE_WINTER)) {
            return true;
        } else {
            return false;
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateSelective(ProductSaveAO product) throws Exception {
        ZyProductInfo originalProduct = productInfoBaseService.selectByPreKey(product.getId());
        if (originalProduct == null) {
            throw new Exception("修改的商品不存在");
        }
        ZyProductInfo productUpdate = getProduct(product);
        //更换商品课程类型
        if (productUpdate.getStageId() == null) {
            ZyProductStage stage = getStage(product);
            if (stage.getBeginDay() == null || stage.getEndDay() == null) {
                throw new RequestParamNullException("上课时间");
            }
            zyProductStageBaseService.saveUseGeneratedKeys(stage);
            zyProductStageBaseService.deleteFromDisk(originalProduct.getStageId());
            productUpdate.setStageId(stage.getId());
        } else {
            Integer stageId = productUpdate.getStageId();
            ZyProductStage updateStage = zyProductStageBaseService.selectByPreKey(stageId);
            if (updateStage.getType().equals(ProductStageTypeEnum.NORMAL)) {
                if (product.getBeginDay() == null || product.getEndDay() == null) {
                    throw new RequestParamNullException("上课时间");
                }
                updateStage.setBeginDay(product.getBeginDay())
                        .setEndDay(product.getEndDay());
                zyProductStageBaseService.updateByPreKey(updateStage);
            }
        }
        productInfoBaseService.update(productUpdate);
    }

    @Override
    public ZyProductInfo getProduct(ProductSaveAO product) {
        ZyProductInfo productInfo = new ZyProductInfo();
        productInfo
                .setCourseId(product.getCourseId())
                .setType(product.getType())
                .setId(product.getId())
                .setBeginTime(product.getBeginTime())
                .setClassId(product.getClassId())
                .setClassRule(product.getClassRule())
                .setEndTime(product.getEndTime())
                .setDescriptionImgUrl(product.getDescriptionImgUrl())
                .setProductImgUrl(product.getProductImgUrl())
                .setProductName(product.getProductName())
                .setPrice(product.getPrice())
                .setStageId(product.getStageId())
                .setPeriod(ProductPeriodEnum.getProductPeriod(product.getBeginTime()));
        return productInfo;
    }

    @Override
    public ZyProductStage getStage(ProductSaveAO productSaveAO) {
        ZyProductStage stage = new ZyProductStage();
        stage.setBeginDay(productSaveAO.getBeginDay())
                .setEndDay(productSaveAO.getEndDay())
                .setIfDelete(false)
                .setType(ProductStageTypeEnum.NORMAL)
                .setCreateTime(new Date());
        return stage;
    }

    @Override
    public ProductVO getProductAndStageByPreKey(Integer id) {
        return productInfoBaseService.selectProductAndStageByProductId(id);
    }

    @Override
    public List<ZyCourseVO> getCourseInfo(String courseName) {
        CourseQuery query = new CourseQuery();
        query.setCourseName(courseName);
        List<ZyCourseVO> courses = zyCourseInfoMapper.getCourseByCourseQuery(query);
        courses.forEach(
                c -> {
                    c.setClassInfos(null);
                    c.setDescription(null);
                    c.setImageUrl(null);
                }
        );
        return courses;
    }

    @Override
    public List<SelectBean> getClassInfo(Integer courseId, String className, DataActionEnum action, Integer productId) {
        ZyCourseInfo course = zyCourseInfoMapper.selectByPrimaryKey(courseId);
        Boolean ifFilterExpireData = false;
        if (course.getQuarter().equals(CourseQuarterEnum.COURSE_EXPERIENCE)) {
            ifFilterExpireData = true;
        }
        List<ZyClassVO> classVOs = zyClassInfoMapper.getByCourseId(courseId, ifFilterExpireData);
        List<SelectBean> selectBeans = classVOs.stream().map(c -> new SelectBean(c.getClassName(), c.getId(), false)).collect(Collectors.toList());
        List<ZyProductInfo> productInfos = productInfoBaseService.selectAll();
        Set<Integer> usedClassIds = productInfos.stream().map(ZyProductInfo::getClassId).collect(Collectors.toSet());
        selectBeans.stream().filter(b -> usedClassIds.contains(Integer.valueOf(b.getValue().toString())))
                .forEach(b -> b.setIfReadOnly(true));
        if (DataActionEnum.UPDATE.equals(action)) {
            //如果是修改动作,仍然可以选择当前班级
            ZyProductInfo currentProduct = productInfoBaseService.selectByPreKey(productId);
            if (currentProduct != null) {
                selectBeans.stream().filter(b -> b.getValue().equals(currentProduct.getClassId()))
                        .forEach(b -> b.setIfReadOnly(false));
            }
        }
        selectBeans = selectBeans.stream().sorted((o1, o2) -> Boolean.compare(o1.getIfReadOnly(), o2.getIfReadOnly())).collect(Collectors.toList());
        return selectBeans;
    }

    @Override
    public void productUpperOrLowerShelf(Integer productId, Boolean productStatus) throws Exception {
        ZyProductInfo originalProduct = productInfoBaseService.selectByPreKey(productId);
        if (originalProduct == null) {
            throw new Exception("该商品不存在");
        }
        if (productStatus.equals(originalProduct.getIfUpperShelf())) {
            throw new Exception("不要进行重复的动作");
        }
        if (productStatus) {
            if (originalProduct.getStageId() == null
                    || originalProduct.getType() == null
                    || originalProduct.getBeginTime() == null
                    || originalProduct.getClassId() == null
                    || originalProduct.getClassRule() == null
                    || originalProduct.getCourseId() == null
                    || StringUtils.isEmpty(originalProduct.getDescriptionImgUrl())
                    || StringUtils.isEmpty(originalProduct.getProductImgUrl())
                    || originalProduct.getEndTime() == null
                    || originalProduct.getPrice() == null
                    || StringUtils.isEmpty(originalProduct.getProductName())) {
                throw new Exception("商品信息不完整,无法上架!");

            }
        }
        ZyProductInfo param = new ZyProductInfo();
        param.setId(productId);
        param.setIfUpperShelf(productStatus);
        productInfoBaseService.update(param);
    }

    @Override
    public List<ZyProductStage> getProductStage() {
        ZyProductStage param = new ZyProductStage();
        param.setType(ProductStageTypeEnum.STAGE);
        param.setIfDelete(false);
        List<ZyProductStage> data = zyProductStageBaseService.selectListByZyProductStage(param);
        if (CollectionUtils.isNotEmpty(data)) {
            data.forEach(
                    s -> {
                        s.setStageName(String.format("%s(%s~%s)", s.getStageName(), DateUtil.date2Str(s.getBeginDay(), DEFAULT_FORMAT_PATTERN_5), DateUtil.date2Str(s.getEndDay(), DEFAULT_FORMAT_PATTERN_5)));
                    }
            );
        }
        return data;
    }

    @Override
    public PageData<ProductListVO> getProductListForPc(ProductListQuery query) {

        PageHelper.startPage(query.getPage(), query.getRows());
        List<ProductListVO> productListVOs = zyProductInfoMapper.getProductListForPc(query.getProductName(), query.getClassName(), query.getCourseName(), query.getIfUpperShelf());

        PageInfo<ProductListVO> pageInfo = new PageInfo<>(productListVOs);
        PageData<ProductListVO> pageData = PageDataUtil.getPageData(pageInfo);
        return pageData;
    }

    @Override
    public List<SelectBean> getProductQueryGrade() {
        List<GradeEnum> grades = productInfoBaseService.getUpperProductGrade();
        List<SelectBean> gradeBeans = grades.stream()
                .sorted(Comparator.comparing(GradeEnum::getOrder))
                .map(g -> new SelectBean(g.getDescription(), g.name()))
                .collect(Collectors.toList());
        return gradeBeans;
    }

    @Override
    public List<SelectBean> getProductQueryDate(Integer courseId) {
        ZyCourseInfo courseInfo = zyCourseInfoMapper.selectByPrimaryKey(courseId);
        List<SelectBean> res = null;
        if (COURSE_WINTER.equals(courseInfo.getQuarter()) || COURSE_SUMMER.equals(courseInfo.getQuarter())) {
            List<ZyProductStage> stages = zyProductStageBaseService.getUpperProductStage(courseId);
            List<SelectBean> stagesList = stages.stream()
                    .sorted(Comparator.comparing(ZyProductStage::getBeginDay))
                    .map(s -> new SelectBean(String.format("%s(%s~%s)", s.getStageName(), DateUtil.date2Str(s.getBeginDay(), DEFAULT_FORMAT_PATTERN_5), DateUtil.date2Str(s.getEndDay(), DEFAULT_FORMAT_PATTERN_5)), s.getId(), "stageId"))
                    .collect(Collectors.toList());
            res = stagesList;
        } else {
            List<ProductClassRuleEnum> classRule = productInfoBaseService.getUpperProductClassRule(courseId);
            List<SelectBean> rules = classRule.stream()
                    .sorted(Comparator.comparing(ProductClassRuleEnum::getOrder))
                    .map(r -> new SelectBean(r.getDesc(), r.name(), "classRule"))
                    .collect(Collectors.toList());
            res = rules;
        }
        return res;
    }

    @Override
    public List<SelectBean> getProductQueryTime(Integer courseId, Integer stageId, ProductClassRuleEnum classRule) {
        List<ZyProductInfo> productInfos = productInfoBaseService.getUpperProductPeriod(courseId, stageId, classRule);
        List<ProductPeriodEnum> period = productInfos.stream().map(ZyProductInfo::getPeriod).distinct().collect(Collectors.toList());
        List<SelectBean> periods = period.stream()
                .sorted()
                .map(p -> new SelectBean(p.getDesc(), p.name(), "period"))
                .collect(Collectors.toList());
        return periods;
    }

    @Override
    public List<ProductStudentGroupVO> getProductGroup(GradeEnum grade) {
        List<ProductStudentGroupVO> data = zyProductInfoMapper.getProductGroup(grade);
        if (CollectionUtils.isNotEmpty(data)) {
            data.forEach(p -> {
                if (p.getCourseQuarterEn() != null) {
                    p.setCourseQuarterCh(p.getCourseQuarterEn().getDescription());
                }

            });
        }
        return data;
    }

    @Override
    public PageData<ProductStudentListVO> getStudentProductList(ProductStudentListQuery query) {
        PageHelper.startPage(query.getPage(), query.getRows());
        List<ProductStudentListVO> productStudentList = zyProductInfoMapper.getStudentProductList(query.getCourseId(), query.getProductStageId(), query.getClassRule(), query.getPeriod());
        PageInfo<ProductStudentListVO> pageInfo = new PageInfo<>(productStudentList);
        PageData<ProductStudentListVO> pageData = PageDataUtil.getPageData(pageInfo);
        pageData.getData().forEach(
                p -> {
                    if (p.getClassRule() != null) {
                        p.setClassRuleCh(p.getClassRule().getDesc());
                    }
                    if (p.getCourseQuarter() != null) {
                        p.setCourseQuarterCh(p.getCourseQuarter().getDescription());
                    }
                    if (p.getGrade() != null) {
                        p.setGradeCh(p.getGrade().getDescription());
                    }
                });
        return pageData;
    }

    @Override
    public ProductStudentListVO getStudentProductInfoByProductId(Integer productId, String userAccount) {
        ProductStudentListVO vo = zyProductInfoMapper.getStudentProductInfoByProductId(productId);
        if (vo.getClassRule() != null) {
            vo.setClassRuleCh(vo.getClassRule().getDesc());
        }
        if (vo.getCourseQuarter() != null) {
            vo.setCourseQuarterCh(vo.getCourseQuarter().getDescription());
        }
        if (orderMapper.checkHaveBuyProduct(userAccount, vo.getClassId())) {
            vo.setIfHasPurchased(true);
        } else {
            vo.setIfHasPurchased(false);
        }
        return vo;
    }

    @Override
    public List<SaleCourseVO> productMsgForSale(GradeEnum grade) {
        List<SaleCourseVO> list = productInfoBaseService.getProductCourseInfo(grade);
        if (CollectionUtils.isNotEmpty(list)) {
            list.forEach(p -> {
                p.setQuarterCh(p.getQuarter().getDescription());
                p.setStudentAvailable(productInfoBaseService.getStudentAvailable(p.getCourseId()));
            });
        }
        return list;
    }

    @Override
    public Map<String, Object> courseDetailsForSale(SaleCourseDetailsQuery query) {
        Integer courseId = query.getCourseId();
        Map<String, Object> res = new HashMap<>(4);
        ZyCourseInfo course = zyCourseInfoMapper.selectByPrimaryKey(courseId);
        res.put("courseName", course.getCourseName());
        List<SaleTeacherStatus> teacherStatuses = productInfoBaseService.productTeacherStatus(courseId);
        Map<String, SaleTeacherStatus> teacherStatusesMap = teacherStatuses.stream().collect(Collectors.toMap(SaleTeacherStatus::getTeacherAccount,v->v));
        List<SaleCourseDetailsVO> details = productInfoBaseService.getSaleCourseDetails(query);
        if (CollectionUtils.isNotEmpty(details)) {
            Map<String, List<SaleCourseDetailsVO>> accountDetailsMap = details.stream().collect(Collectors.groupingBy(SaleCourseDetailsVO::getTeacherAccount));
            for (Map.Entry<String, List<SaleCourseDetailsVO>> e : accountDetailsMap.entrySet()) {
                Map<SaleStageVO, List<SaleCourseDetailsVO>> stageMap = e.getValue().stream().collect(Collectors.groupingBy(d -> new SaleStageVO(d.getStageId(), d.getStageName(),d.getClassRule())));
                List<SaleStageVO> stageList = stageMap.entrySet()
                                .stream()
                                .map(se -> {
                                    se.getKey().setProducts(
                                            se.getValue()
                                                    .stream()
                                                    .map(d -> new SaleProductVO(d.getBeginTime(), d.getEndTime(), d.getClassCount(), d.getCurrentClassCount()))
                                                    .collect(Collectors.toList()));
                                    return se.getKey();
                                }).collect(Collectors.toList());
                teacherStatusesMap.get(e.getKey()).setStage(stageList);
            }
        }
        res.put("teachers", teacherStatuses);
        return res;
    }

    @Override
    public List<SaleDateParam> getCourseDetailsParams(SaleCourseDetailsQuery query) {
        List<ZyProductInfo> productInfos = productInfoBaseService.getUpperProductPeriod(query.getCourseId(), query.getStageId(), query.getClassRule());
        List<SaleDateParam> dateParams = productInfos.stream()
                .sorted((o1,o2)->o1.getBeginTime().before(o2.getBeginTime())?-1:1)
                .map(p->new SaleDateParam(p.getBeginTime(),p.getEndTime()))
                .distinct()
                .collect(Collectors.toList());
        return dateParams;
    }
}
